#include "IslandEvolution.h"

IslandEvolution::IslandEvolution(int epochSize, int migrateSize)
{
    this->migrateSize = migrateSize;
    this->migrateCount = 0;
    this->epochSize = epochSize;
    this->finalValue1 = 0;
    epochCount = 0;
}
IslandEvolution::~IslandEvolution() {
    for(int i=0;i< evolutionEngines.size();i++) {
        delete evolutionEngines.at(i);
    }
    evolutionEngines.clear();
}

bool IslandEvolution::evolve() {
    for(int i=0;i< evolutionEngines.size();i++) {
        finished = evolutionEngines.at(i)->evolve();
    }
    if(migrateCount >= migrateSize) {
        migrate();
        migrateCount = 0;
    } else {
        migrateCount++;
    }
    return finished;
}

void IslandEvolution::addEvolutionEngine(EvolutionEngine* engine) {
    evolutionEngines.push_back(engine);
}
void IslandEvolution::migrate() {

    Candidate* winner1;
    Candidate* winner2;
    Candidate* winner3;
    Candidate* winner4;
    for(int i=0;i<evolutionEngines.size();i++) {
        winner1 = evolutionEngines.at(i)->migrateCandidate();
        winner2 = evolutionEngines.at((i+1)%evolutionEngines.size())->migrateCandidate();
        winner3 = evolutionEngines.at(i)->migrateCandidate();
        winner4 = evolutionEngines.at((i+1)%evolutionEngines.size())->migrateCandidate();
        evolutionEngines.at((i+1)%evolutionEngines.size())->introduceImmigrant(winner1);
        evolutionEngines.at((i))->introduceImmigrant(winner2);
        evolutionEngines.at((i+1)%evolutionEngines.size())->introduceImmigrant(winner3);
        evolutionEngines.at((i))->introduceImmigrant(winner4);
        if(i==0) {
            this->fitness1 = winner1->getFitness();
            this->fitness2 = winner2->getFitness();
            this->fitness3 = winner3->getFitness();
            this->fitness4 = winner4->getFitness();
        }
    }
}
void IslandEvolution::setTargetValue(float targetValue) {
    for(int i=0;i< evolutionEngines.size();i++) {
        evolutionEngines.at(i)->setTargetValue(targetValue);
    }
}
Candidate* IslandEvolution::getWinner() {
    if(fitness1<fitness2) {
        return evolutionEngines.at(0)->getWinner();
    } else {
        return evolutionEngines.at(1)->getWinner();
    }
}

float IslandEvolution::getFitness1() {
    return this->fitness1;
}
float IslandEvolution::getFitness2() {
    return this->fitness2;
}
float IslandEvolution::getFitness3() {
    return this->fitness3;
}
float IslandEvolution::getFitness4() {
    return this->fitness4;
}
float IslandEvolution::getFinalValue1() {
    return this->finalValue1 = evolutionEngines.at(0)->getFinalValue();
}
float IslandEvolution::getFinalValue2() {
    return this->finalValue1 = evolutionEngines.at(1)->getFinalValue();
}
float IslandEvolution::getFinalValue3() {
    return this->finalValue3;
}
float IslandEvolution::getFinalValue4() {
    return this->finalValue4;
}
